<?php
class system_concept_abstract {
	protected $_adapter = null;
	protected $_models = array();
	protected $_modelsPrimayKey = array();
	protected $_main = null;
	protected $_join = array();
	protected $_joinLeft = array();
	protected $_cnames = array(); // cname=>name
	protected $_cols = array(); // modelName=>array();
	protected $_defaultValues = array();
	protected $_defaultWhere = array();
	protected $_defaultOrWhere = array();
	
	/**
	 * 用来解决两个表中字段关联用的
	 */
	protected $_linkCols = array();
	
	protected $_rowClass = 'system_concept_row';
	protected $_rowsetClass = 'system_concept_rowset';
	
	/**
	 * 
	 * @param unknown_type $defaultValues 默认值 
	 * @param unknown_type $defaultWhere 默认条件
	 * 
	 */
	public function __construct($defaultValues = array(), $defaultWhere = array()) {
		
		$this->setDefaultValues($defaultValues);
		$this->setDefaultWhere($defaultWhere);
		$this->init();
	}
	
	public function getDefaultValues() {
		return $this->_defaultValues;
	}
	public function getDefaultWhere() {
		return $this->_defaultWhere;
	}
	
	public function setDefaultValues(array $values) {
		$this->_defaultValues = $values;
		return $this;
	}
	/**
	 * return $this
	 * @param unknown_type $key
	 * @param unknown_type $val
	 */
	public function addDefaultValue($key, $val) {
		$this->_defaultValues[$key] = $val;
		return $this;
	}
	public function addDefaultWhere($key, $val = null) {
		if($val==null) {
			$this->_defaultWhere[] = $key;
		} else {
			$this->_defaultWhere[$key] = $val;
		}
		return $this;
	}
	
	public function setDefaultWhere(array $where) {
		$this->_defaultWhere = $where;
		return $this;
	}
	
	/**
	 * 设置数据库连接对象
	 * @param system_db_adapter_abstract $adapter
	 * @return system_concept_abstract
	 */
	public function setAdapter(system_db_adapter_abstract $adapter) {
		$this->_adapter = $adapter;
		return $this;
	}
	/**
	 * @return system_db_adapter_abstract
	 */
	public function getAdapter() {
		if(null===$this->_adapter) {
			$this->setAdapter(system_db::getAdapter());
		}
		return $this->_adapter;
	}
	protected $_select;
	/**
	 * @return system_db_select
	 */
	public function select() {
		
		$select = $this->getAdapter()->select();
		
		if($this->_main==null) {
			throw new system_exception('The concept can no set model');
		}
		$mainModelCname = $this->_getModelCname($this->_main);
		$select->from($this->getModel($mainModelCname)->getName().' AS '.$mainModelCname, $this->_getMOdelSelectCols($mainModelCname));
		//$select instanceof system_db_select;
		

		foreach($this->_join as $model => $on) {
			$modelCname = $this->_getModelCname($model);
			$select->join($this->getModel($modelCname)->getName().' AS '.$modelCname, $on, $this->_getMOdelSelectCols($modelCname));
		}
		foreach($this->_joinLeft as $model => $on) {
			$modelCname = $this->_getModelCname($model);
			$select->joinLeft($this->getModel($modelCname)->getName().' AS '.$modelCname, $on, $this->_getMOdelSelectCols($modelCname));
		}
		
		return $select;
	}
	
	/**
	 * 设置主数据模块类
	 * @param $name model的类名
	 * @param $cname model的类别名
	 * @return system_concept_abstract
	 */
	public function setModel($name, $cname = null) {
		$cname===null&&$cname = $name;
		$this->_cnames[$cname] = $name;
		$this->_main = $name;
		return $this;
	}
	
	/**
	 * 设置关联model类
	 * @param string $name model 类名
	 * @param string $on 关系条件
	 * @param string $cname model的别名
	 * @return system_concept_abstract
	 */
	public function setJoinModel($name, $on, $cname = null) {
		$cname===null&&$cname = $name;
		$this->_cnames[$cname] = $name;
		$this->_join[$name] = $on;
		return $this;
	}
	
	/**
	 * 设置 关联model 的左关联
	 * @param string $name
	 * @param string $on
	 * @param string $cname
	 * @return system_concept_abstract
	 */
	public function setJoinLeftModel($name, $on, $cname = null) {
		$cname===null&&$cname = $name;
		$this->_cnames[$cname] = $name;
		$this->_joinLeft[$name] = $on;
		return $this;
	}
	
	/**
	 * 得到主model 的名称
	 * @return string
	 */
	public function getMainModelName() {
		return $this->_getModelCname($this->_main);
	}
	
	/**
	 * 得到主model对象
	 * @return system_db_table
	 */
	public function getMainModel() {
		return $this->getModel($this->getMainModelName());
	}
	
	/**
	 * 得到model对象
	 * @param unknown_type $cname
	 * @return system_db_table
	 */
	public function getModel($cname) {
		$modelName = $this->_getModelName($cname);
		if(!isset($this->_models[$modelName])) {
			$this->_models[$modelName] = new $modelName();
		}
		return $this->_models[$modelName];
	}
	
	/**
	 * 得到所有model
	 * @return ArrayIterator
	 */
	public function getModels() {
		$models = array();
		foreach($this->_cnames as $k => $v) {
			$models[$k] = $this->getModel($k);
		}
		return $models;
	}
	
	/**
	 * 设置model的字段
	 * @param string $cname
	 * @param string $colName
	 * @param string $colCname
	 * @return system_concept_abstract
	 */
	public function setModelCol($cname, $colName, $colCname = null) {
		$colCname===null&&$colCname = $colName;
		$modelName = $this->_getModelName($cname);
		$this->_cols[$modelName][$colCname] = $colName;
		$this->parseColsLink($modelName, $colCname);
		return $this;
	}
	
	public function cleanModelCols() {
		$this->_cols = array();
		return $this;
	}
	
	public function removeModelCols($modelCname) {
		$m = $this->_getModelName($modelCname);
		if(isset($this->_cols[$m])) {
			unset($this->_cols[$m]);
		}
		return $this;
	}
	
	public function removeCol($cname) {
		foreach($this->_cols as $m) {
			foreach($m as $colcname => $colname) {
				if($cname==$colcname) {
				
				}
			}
		}
		return $this;
	}
	
	//用来解析字段关联
	public function parseColsLink($modelName, $colCname) {
		foreach($this->_cols as $m => $col) {
			if($m==$modelName) {
				continue;
			}
			if(isset($col[$colCname])) {
				$this->_linkCols[$modelName][$colCname] = $m;
				$this->_linkCols[$m][$colCname] = $modelName;
			}
		}
	}
	/**
	 * 得到其它model中有同别名的model
	 * @param unknown_type $modelName
	 * @param unknown_type $colCname
	 */
	public function getColsLink($modelName, $colCname) {
		if(isset($this->_linkCols[$modelName][$colCname])) {
			return $this->_linkCols[$modelName][$colCname];
		} else {
			return null;
		}
	}
	
	/**
	 * 设置 model 字段名
	 * @param string $cname
	 * @param array $cols
	 * @return system_concept_abstract
	 */
	public function setModelCols($cname, $cols) {
		foreach($cols as $k => $v) {
			if(is_numeric($k)) {
				$colName = $colCname = $v;
			} else {
				$colName = $k;
				$colCname = $v;
			}
			$this->setModelCol($cname, $colName, $colCname);
		}
		return $this;
	}
	
	/**
	 * 移除字段
	 * @param unknown_type $cname
	 */
	public function removeModelCol($colCname) {
		foreach($this->_cols as $m => $values) {
			foreach($values as $k => $v) {
				if($k==$colCname) {
					unset($this->_cols[$m][$k]);
					return true;
				}
			}
		}
	}
	
	/**
	 * 得到model所有字段
	 * @param string $cname
	 * @return ArrayIterator
	 */
	public function getModelCols($cname) {
		$name = $this->_getModelName($cname);
		if(isset($this->_cols[$name])) {
			return $this->_cols[$name];
		}
		return array();
	}
	
	public function getCols($cname = null) {
		if($cname==null) {
			return $this->_cols;
		} else {
			return $this->_cols[$this->_getModelName($cname)];
		}
	}
	public function getColRealName($colCname) {
		foreach($this->_cols as $m => $cols) {
			foreach($cols as $k => $v) {
				if($k==$colCname) {
					return array($this->_getModelCname($m) => $v);
				}
			}
		}
	}
	
	public function getColModelCname($colCname) {
		foreach($this->_cols as $m => $cols) {
			foreach($cols as $k => $v) {
				if($k==$colCname) {
					return $m;
				}
			}
		}
		throw new system_exception('can not found the col '.$colCname);
	}
	/**
	 * 反回model的主键数组
	 * @param unknown_type $cname
	 */
	public function getModelsPrimaryKey($cname) {
		$name = $this->_getModelName($cname);
		if(!isset($this->_modelsPrimayKey[$name])) {
			$primaryKey = $this->getModel($cname)->getPrimaryKey();
			$cols = array();
			foreach($primaryKey as $v) {
				$cols['pk_'.$cname.'_'.$v] = $v;
			}
			$this->_modelsPrimayKey[$name] = $cols;
		}
		return $this->_modelsPrimayKey[$name];
	}
	protected function _getModelSelectCols($cname) {
		$cols = array();
		foreach($this->getModelCols($cname) as $k => $v) {
			if(is_numeric($k)) {
				$vcname = $kcname = $v;
			} else {
				$vcname = $v;
				$kcname = $k;
			}
			$cols[] = $vcname.' AS '.$kcname;
		}
		foreach($this->getModelsPrimaryKey($cname) as $k => $v) {
			$cols[] = $v.' AS '.$k;
		}
		
		return $cols;
	}
	protected function _getModelCname($name) {
		$cname = array_search($name, $this->_cnames);
		if($cname===null) {
			throw new system_exception('Can not set model name : '.$name);
		}
		return $cname;
	}
	protected function _getModelName($cname) {
		if(isset($this->_cnames[$cname])) {
			return $this->_cnames[$cname];
		}
		throw new system_exception('Can not set the model cname : '.$cname);
	}
	
	public function setRowClass($rowClass) {
		$this->_rowClass = $rowClass;
		return $this;
	}
	public function getRowClass() {
		return $this->_rowClass;
	}
	public function setRowsetClass($rowsetClass) {
		$this->_rowsetClass = $rowsetClass;
		return $this;
	}
	
	/**
	 * 反回rowset的类名
	 */
	public function getRowsetClass() {
		return $this->_rowsetClass;
	}
	
	/***
	 * 取得当前concept的数据结构
	 */
	public function getRowCols($data = array()) {
		$data = $data+$this->getDefaultValues();
		
		$colsData = array();
		foreach($this->getCols() as $m => $value) {
			foreach($value as $k => $v) {
				if(isset($data[$k])) {
					$colsData[$k] = $data[$k];
				} else {
					$colsData[$k] = null;
				}
			}
		}
		return $colsData;
	}
	
	/**
	 * 创建一个空的数据对象 row
	 * @param unknown_type $data
	 * @return system_concept_row
	 */
	public function create($data = array()) {
		
		$rowClass = $this->getRowClass();
		return new $rowClass($this->getRowCols($data), $this);
	}
	
	/**
	 * 查询一条空的数据对象row
	 * @param array|string $where 查询条件(可以用数组)
	 * @return system_db_table_row
	 */
	protected function _fetch($where = array(), $order = null) {
		$select = $this->select();
		if($this->_defaultWhere) {
			$where = array_merge((array) $where, (array) $this->_defaultWhere);
		}
		if(is_string($where)) {
			$where = array($where);
		}
		$select = $this->_where($select, $where+$this->_defaultWhere);
		if(null!==$order) {
			$select = $this->_order($select, $order);
		}
		$select->limit(1);
		return $this->getAdapter()->fetchRow($select);
	}
	
	/**
	 * 
	 * @param $where
	 * @param $order
	 * @param $count
	 * @param $page
	 * @return system_db_table_rowset
	 */
	protected function _fetchAll($where = array(), $order = null, $count = null, $page = null) {
		$select = $this->select();
		if($this->_defaultWhere) {
			$where = array_merge((array) $where, (array) $this->_defaultWhere);
		}
		$select = $this->_where($select, $where);
		if(null!==$order) {
			$select = $this->_order($select, $order);
		}
		if($count!==null||$page!==null) {
			$select->limitPage($page, $count);
		}
		return $select->query()->fetchAll();
	}
	
	/**
	 * 查询一条数据对象row
	 * @param array|string $where 输入查询条件(可以用数组或字符串) 
	 * @return system_concept_row
	 */
	public function fetch($where = null, $order = null) {
		$data = $this->_fetch($where, $order);
		if(!$data) {
			return null;
		}
		$rowClass = $this->getRowClass();
		return new $rowClass($data, $this);
	}
	
	/**
	 * 查询多条数据反回一个数组对象列表
	 * @param array|string $where 输入查询条件（可以是数组或字符)
	 * @param array|string $order 数据排序字段 (可以是数组或字符)
	 * @param int $count 每次查询得到的数量
	 * @param int $page 当前查询页码数
	 * @return system_concept_rowset
	 */
	public function fetchAll($where = null, $order = null, $count = null, $page = null) {
		$list = $this->_fetchAll($where, $order, $count, $page);
		$rowsetClass = $this->getRowsetClass();
		return new $rowsetClass($list, $this, $this->getRowClass());
	}
	
	/**
	 * 根据条件求数据条总数
	 * @param array|string $where
	 * @return int
	 */
	public function fetchCount($where = array()) {
		$select = $this->select();
		if($this->_defaultWhere) {
			$where = array_merge((array) $where, (array) $this->_defaultWhere);
		}
		$select = $this->_where($select, $where);
		return (int) $this->getAdapter()->fetchOne($select->getCountSelect());
	}
	
	/**
	 * rowset exp method
	 * @param system_concept_row $row
	 * @return true|false
	 * 
	 */
	public function update(system_concept_row $row) {
		$cols = array();
		
		foreach($row->_updatedData as $k => $v) {
			
			$real = $this->getColRealName($k);
			$modelName = key($real);
			$colName = $real[$modelName];
			$pk = $this->getModelsPrimaryKey($modelName);
			
			if(!array_search($colName, $pk)) {
				$cols[$modelName][$colName] = $v;
			}
		}
		$update = array();
		foreach($cols as $model => $cols) {
			$where = $row->_getPrimaryKeyBond($model);
			$this->getModel($model)->update($cols, $where);
		}
		return true;
	}
	
	/**
	 * 处理select 的 where
	 * @param system_db_select $select
	 * @param $where
	 * @return system_db_select
	 */
	protected function _where(system_db_select $select, $where) {
		$where = (array) $where;
		foreach($where as $key => $val) {
			// is $key an int?
			if(is_int($key)) {
				// $val is the full condition
				if(is_array($val)) {
					$select = $this->_where($select, $val);
				} else {
					$select->where($val);
				}
			} else {
				// $key is the condition with placeholder,
				// and $val is quoted into the condition
				$select->where($key, $val);
			}
		}
		
		return $select;
	}
	
	/**
	 * 组成排序sql
	 * @param system_db_select $select
	 * @param unknown_type $order
	 * @return system_db_select
	 */
	protected function _order(system_db_select $select, $order) {
		if(!is_array($order)) {
			$order = array($order);
		}
		
		foreach($order as $val) {
			if(is_array($val)) {
				$select = $this->_order($select, $val);
			} else {
				$select->order($val);
			}
		}
		
		return $select;
	}
	
	/**
	 * 
	 * @param system_concept_row $row
	 * @param array|bool $all
	 * @return ture|flase
	 */
	public function delete(system_concept_row $row, $all = false) {
		if($all) {
			if($all===true) {
				$all = $this->getModels();
			} elseif(is_array($all)) {
				$list = array();
				foreach($all as $v) {
					$list[$v] = $this->getModel($v);
				}
				$all = &$list;
			} elseif(is_string($all)) {
				return $this->delete($row, implode(',', $all));
			} else {
				return false;
			}
			foreach($all as $k => $m) {
				if(!!($pkw = $row->_getPrimaryKeyBond($k))) {
					$m->delete($pkw);
				}
			}
		} else {
			if(!!($pkw = $row->_getPrimaryKeyBond($this->getMainModelName()))) {
				$this->getMainModel()->delete($pkw);
			}
		}
		return true;
	}
	
	/**
	 * 得到当概念对象的分页对象
	 * @return system_paginator_adapter_concept
	 */
	public function getPaginatorAdapter() {
		return new system_paginator_adapter_concept($this);
	}
	
	public function __destruct() {
		//foreach($this AS $k=>$v) {
	//	unset($k);
	//}
	//echo "concept destruct \r\n";
	}
}